home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 49 / Amiga Format CD49 (2000-01-17)(Future Publishing)(GB)(Track 1 of 3)[!][issue 2000-02].iso / -serious- / graphics / gnuplot / gnuplot-3.7.1src / gnuplot-3.7.1 / graph3d.c < prev    next >
Text File  |  1999-11-29  |  58KB  |  1,977 lines

  1. #ifndef lint, place, &x, &y)Sid = "$Id: graph3d.c,v 1.13.2.4 1999/10/19 13:31:49 lhecking Exp $";
  2. #endif
  3.  
  4. /* GNUPLOT - graph3d.c */
  5.  
  6. /*[
  7.  * Copyright 1986 - 1993, 1998   Thomas Williams, Colin Kelley
  8.  *
  9.  * Permission to use, copy, and distribute this software and its
  10.  * documentation for any purpose with or without fee is hereby granted,
  11.  * provided that the above copyright notice appear in all copies and
  12.  * that both that copyright notice and this permission notice appear
  13.  * in supporting documentation.
  14.  *
  15.  * Permission to modify the software is granted, but not the right to
  16.  * distribute the complete modified source code.  Modifications are to
  17.  * be distributed as patches to the released version.  Permission to
  18.  * distribute binaries produced by compiling modified sources is granted,
  19.  * provided you
  20.  *   1. distribute the corresponding source modifications from the
  21.  *    released version in the form of a patch file along with the binaries,
  22.  *   2. add special version identification to distinguish your version
  23.  *    in addition to the base release version number,
  24.  *   3. provide your name and address as the primary contact for the
  25.  *    support of your modified version, and
  26.  *   4. retain our contact information in regard to use of the base
  27.  *    software.
  28.  * Permission to distribute the released version of the source code along
  29.  * with corresponding source modifications in the form of a patch file is
  30.  * granted with same provisions 2 through 4 for binary distributions.
  31.  *
  32.  * This software is provided "as is" without express or implied warranty
  33.  * to the extent permitted by applicable law.
  34. ]*/
  35.  
  36.  
  37. /*
  38.  * AUTHORS
  39.  *
  40.  *   Original Software:
  41.  *       Gershon Elber and many others.
  42.  *
  43.  * 19 September 1992  Lawrence Crowl  (crowl@cs.orst.edu)
  44.  * Added user-specified bases for log scaling.
  45.  *
  46.  * 3.6 - split graph3d.c into graph3d.c (graph),
  47.  *                            util3d.c (intersections, etc)
  48.  *                            hidden3d.c (hidden-line removal code)
  49.  *
  50.  */
  51.  
  52. #include "plot.h"
  53. #include "setshow.h"
  54.  
  55. static int p_height;
  56. static int p_width;        /* pointsize * t->h_tic */
  57. static int key_entry_height;    /* bigger of t->v_size, pointsize*t->v_tick */
  58.  
  59. int suppressMove = 0;        /* to prevent moveto while drawing contours */
  60.  
  61. /*
  62.  * hidden_line_type_above, hidden_line_type_below - controls type of lines
  63.  *   for above and below parts of the surface.
  64.  * hidden_no_update - if TRUE lines will be hidden line removed but they
  65.  *   are not assumed to be part of the surface (i.e. grid) and therefore
  66.  *   do not influence the hidings.
  67.  * hidden_active - TRUE if hidden lines are to be removed.
  68.  */
  69. int hidden_active = FALSE;
  70. int hidden_no_update;        /* HBB 980324: made this visible despite LITE */
  71.  
  72. /* LITE defines a restricted memory version for MS-DOS, which doesn't
  73.  * use the routines in hidden3d.c
  74.  */
  75.  
  76. #ifndef LITE
  77. int hidden_line_type_above, hidden_line_type_below;
  78. #endif /* LITE */
  79.  
  80.  
  81. static double LogScale __PROTO((double coord, TBOOLEAN is_log,
  82.                 double log_base_log, char *what, char *axis));
  83. static void plot3d_impulses __PROTO((struct surface_points * plot));
  84. static void plot3d_lines __PROTO((struct surface_points * plot));
  85. static void plot3d_points __PROTO((struct surface_points * plot));
  86. static void plot3d_dots __PROTO((struct surface_points * plot));
  87. static void cntr3d_impulses __PROTO((struct gnuplot_contours * cntr,
  88.                      struct surface_points * plot));
  89. static void cntr3d_lines __PROTO((struct gnuplot_contours * cntr));
  90. static void cntr3d_points __PROTO((struct gnuplot_contours * cntr,
  91.                    struct surface_points * plot));
  92. static void cntr3d_dots __PROTO((struct gnuplot_contours * cntr));
  93. static void check_corner_height __PROTO((struct coordinate GPHUGE * point,
  94.                      double height[2][2], double depth[2][2]));
  95. static void draw_bottom_grid __PROTO((struct surface_points * plot,
  96.                       int plot_count));
  97. static void xtick_callback __PROTO((int axis, double place, char *text,
  98.                     struct lp_style_type grid));
  99. static void ytick_callback __PROTO((int axis, double place, char *text,
  100.                     struct lp_style_type grid));
  101. static void ztick_callback __PROTO((int axis, double place, char *text,
  102.                     struct lp_style_type grid));
  103. static void setlinestyle __PROTO((struct lp_style_type style));
  104.  
  105. static void boundary3d __PROTO((int scaling, struct surface_points * plots,
  106.                 int count));
  107. #if 0                /* not used */
  108. static double dbl_raise __PROTO((double x, int y));
  109. #endif
  110. static void map_position __PROTO((struct position * pos, unsigned int *x,
  111.                   unsigned int *y, char *what));
  112.  
  113. /* put entries in the key */
  114. static void key_sample_line __PROTO((int xl, int yl));
  115. static void key_sample_point __PROTO((int xl, int yl, int pointtype));
  116. static void key_text __PROTO((int xl, int yl, char *text));
  117.  
  118.  
  119. #if defined(sun386) || defined(AMIGA_SC_6_1)
  120. static double CheckLog __PROTO((TBOOLEAN is_log, double base_log, double x));
  121. #endif
  122.  
  123. /*
  124.  * The Amiga SAS/C 6.2 compiler moans about macro envocations causing
  125.  * multiple calls to functions. I converted these macros to inline
  126.  * functions coping with the problem without loosing speed.
  127.  * (MGR, 1993)
  128.  */
  129. #ifdef AMIGA_SC_6_1
  130. GP_INLINE static TBOOLEAN i_inrange(int z, int min, int max)
  131. {
  132.     return ((min < max) ? ((z >= min) && (z <= max)) : ((z >= max) && (z <= min)));
  133. }
  134.  
  135. GP_INLINE static double f_max(double a, double b)
  136. {
  137.     return (max(a, b));
  138. }
  139.  
  140. GP_INLINE static double f_min(double a, double b)
  141. {
  142.     return (min(a, b));
  143. }
  144.  
  145. #else
  146. # define f_max(a,b) GPMAX((a),(b))
  147. # define f_min(a,b) GPMIN((a),(b))
  148. # define i_inrange(z,a,b) inrange((z),(a),(b))
  149. #endif
  150.  
  151. #define apx_eq(x,y) (fabs(x-y) < 0.001)
  152. #define ABS(x) ((x) >= 0 ? (x) : -(x))
  153. #define SQR(x) ((x) * (x))
  154.  
  155. /* Define the boundary of the plot
  156.  * These are computed at each call to do_plot, and are constant over
  157.  * the period of one do_plot. They actually only change when the term
  158.  * type changes and when the 'set size' factors change. 
  159.  */
  160.  
  161. /* in order to allow graphic.c to use clip_draw_line, we must
  162.  * share xleft, xright, ybot, ytop with graphics.c
  163.  */
  164. extern int xleft, xright, ybot, ytop;
  165.  
  166. int xmiddle, ymiddle, xscaler, yscaler;
  167. static int ptitl_cnt;
  168. static int max_ptitl_len;
  169. static int titlelin;
  170. static int key_sample_width, key_rows, key_cols, key_col_wth, yl_ref;
  171. static int ktitle_lines = 0;
  172.  
  173.  
  174. /* Boundary and scale factors, in user coordinates */
  175. /* x_min3d, x_max3d, y_min3d, y_max3d, z_min3d, z_max3d are local to this
  176.  * file and are not the same as variables of the same names in other files
  177.  */
  178. /*static double x_min3d, x_max3d, y_min3d, y_max3d, z_min3d, z_max3d; */
  179. /* sizes are now set in min_array[], max_array[] from plot.c */
  180. extern double min_array[], max_array[];
  181. extern int auto_array[], log_array[];
  182. extern double base_array[], log_base_array[];
  183.  
  184. /* for convenience while converting to use these arrays */
  185. #define x_min3d min_array[FIRST_X_AXIS]
  186. #define x_max3d max_array[FIRST_X_AXIS]
  187. #define y_min3d min_array[FIRST_Y_AXIS]
  188. #define y_max3d max_array[FIRST_Y_AXIS]
  189. #define z_min3d min_array[FIRST_Z_AXIS]
  190. #define z_max3d max_array[FIRST_Z_AXIS]
  191.  
  192. /* There are several z's to take into account - I hope I get these
  193.  * right !
  194.  *
  195.  * ceiling_z is the highest z in use
  196.  * floor_z   is the lowest z in use
  197.  * base_z is the z of the base
  198.  * min3d_z is the lowest z of the graph area
  199.  * max3d_z is the highest z of the graph area
  200.  *
  201.  * ceiling_z is either max3d_z or base_z, and similarly for floor_z
  202.  * There should be no part of graph drawn outside
  203.  * min3d_z:max3d_z  - apart from arrows, perhaps
  204.  */
  205.  
  206. double ceiling_z, floor_z, base_z;
  207.  
  208. /* and some bodges while making the change */
  209. #define min3d_z min_array[FIRST_Z_AXIS]
  210. #define max3d_z max_array[FIRST_Z_AXIS]
  211.  
  212.  
  213. double xscale3d, yscale3d, zscale3d;
  214.  
  215.  
  216. typedef double transform_matrix[4][4];
  217. transform_matrix trans_mat;
  218.  
  219. static double xaxis_y, yaxis_x, zaxis_x, zaxis_y;
  220.  
  221. /* the co-ordinates of the back corner */
  222. static double back_x, back_y;
  223.  
  224. /* the penalty for convenience of using tic_gen to make callbacks
  225.  * to tick routines is that we cant pass parameters very easily.
  226.  * We communicate with the tick_callbacks using static variables
  227.  */
  228.  
  229. /* unit vector (terminal coords) */
  230. static double tic_unitx, tic_unity;
  231.  
  232. /* (DFK) Watch for cancellation error near zero on axes labels */
  233. #define SIGNIF (0.01)        /* less than one hundredth of a tic mark */
  234. #define CheckZero(x,tic) (fabs(x) < ((tic) * SIGNIF) ? 0.0 : (x))
  235. #define NearlyEqual(x,y,tic) (fabs((x)-(y)) < ((tic) * SIGNIF))
  236.  
  237. /* And the functions to map from user to terminal coordinates */
  238. #define map_x(x) (int)(x+0.5)    /* maps floating point x to screen */
  239. #define map_y(y) (int)(y+0.5)    /* same for y */
  240.  
  241. /* And the functions to map from user 3D space into normalized -1..1 */
  242. #define map_x3d(x) ((x-x_min3d)*xscale3d-1.0)
  243. #define map_y3d(y) ((y-y_min3d)*yscale3d-1.0)
  244. #define map_z3d(z) ((z-floor_z)*zscale3d-1.0)
  245.  
  246.  
  247.  
  248. /* Initialize the line style using the current device and set hidden styles
  249.  * to it as well if hidden line removal is enabled */
  250. static void setlinestyle(style)
  251. struct lp_style_type style;
  252. {
  253.     term_apply_lp_properties(&style);
  254.  
  255. #ifndef LITE
  256.     if (hidden3d) {
  257.     hidden_line_type_above = style.l_type;
  258.     hidden_line_type_below = style.l_type;
  259.     }
  260. #endif /* LITE */
  261. }
  262.  
  263. /* (DFK) For some reason, the Sun386i compiler screws up with the CheckLog 
  264.  * macro, so I write it as a function on that machine.
  265.  *
  266.  * Amiga SAS/C 6.2 thinks it will do too much work calling functions in
  267.  * macro arguments twice, thus I inline theese functions. (MGR, 1993)
  268.  */
  269. #if defined(sun386) || defined(AMIGA_SC_6_1)
  270. GP_INLINE static double CheckLog(is_log, base_log, x)
  271. TBOOLEAN is_log;
  272. double base_log;
  273. double x;
  274. {
  275.     if (is_log)
  276.     return (pow(base_log, x));
  277.     else
  278.     return (x);
  279. }
  280. #else
  281. /* (DFK) Use 10^x if logscale is in effect, else x */
  282. # define CheckLog(is_log, base_log, x) ((is_log) ? pow(base_log, (x)) : (x))
  283. #endif /* sun386 || SAS/C */
  284.  
  285. static double LogScale(coord, is_log, log_base_log, what, axis)
  286. double coord;            /* the value */
  287. TBOOLEAN is_log;        /* is this axis in logscale? */
  288. double log_base_log;        /* if so, the log of its base */
  289. char *what;            /* what is the coord for? */
  290. char *axis;            /* which axis is this for ("x" or "y")? */
  291. {
  292.     if (is_log) {
  293.     if (coord <= 0.0) {
  294.         char errbuf[100];    /* place to write error message */
  295.         (void) sprintf(errbuf, "%s has %s coord of %g; must be above 0 for log scale!",
  296.                what, axis, coord);
  297.         graph_error(errbuf);
  298.     } else
  299.         return (log(coord) / log_base_log);
  300.     }
  301.     return (coord);
  302. }
  303.  
  304. /* And the functions to map from user 3D space to terminal coordinates */
  305. void map3d_xy(x, y, z, xt, yt)
  306. double x, y, z;
  307. unsigned int *xt, *yt;
  308. {
  309.     int i, j;
  310.     double v[4], res[4], /* Homogeneous coords. vectors. */
  311.     w = trans_mat[3][3];
  312.  
  313.     v[0] = map_x3d(x);        /* Normalize object space to -1..1 */
  314.     v[1] = map_y3d(y);
  315.     v[2] = map_z3d(z);
  316.     v[3] = 1.0;
  317.  
  318.     for (i = 0; i < 2; i++) {    /* Dont use the third axes (z). */
  319.     res[i] = trans_mat[3][i];    /* Initiate it with the weight factor */
  320.     for (j = 0; j < 3; j++)
  321.         res[i] += v[j] * trans_mat[j][i];
  322.     }
  323.  
  324.     for (i = 0; i < 3; i++)
  325.     w += v[i] * trans_mat[i][3];
  326.     if (w == 0)
  327.     w = 1e-5;
  328.  
  329.     *xt = (unsigned int) ((res[0] * xscaler / w) + xmiddle);
  330.     *yt = (unsigned int) ((res[1] * yscaler / w) + ymiddle);
  331. }
  332.  
  333.  
  334.  
  335. /* And the functions to map from user 3D space to terminal z coordinate */
  336. int map3d_z(x, y, z)
  337. double x, y, z;
  338. {
  339.     int i, zt;
  340.     double v[4], res, /* Homogeneous coords. vectors. */
  341.     w = trans_mat[3][3];
  342.  
  343.     v[0] = map_x3d(x);        /* Normalize object space to -1..1 */
  344.     v[1] = map_y3d(y);
  345.     v[2] = map_z3d(z);
  346.     v[3] = 1.0;
  347.  
  348.     res = trans_mat[3][2];    /* Initiate it with the weight factor. */
  349.     for (i = 0; i < 3; i++)
  350.     res += v[i] * trans_mat[i][2];
  351.     if (w == 0)
  352.     w = 1e-5;
  353.     for (i = 0; i < 3; i++)
  354.     w += v[i] * trans_mat[i][3];
  355.     zt = ((int) (res * 16384 / w));
  356.     return zt;
  357. }
  358.  
  359. /* borders of plotting area */
  360. /* computed once on every call to do_plot */
  361. static void boundary3d(scaling, plots, count)
  362. TBOOLEAN scaling;        /* TRUE if terminal is doing the scaling */
  363. struct surface_points *plots;
  364. int count;
  365. {
  366.     register struct termentry *t = term;
  367.     int ytlen, i;
  368.  
  369.     titlelin = 0;
  370.  
  371.     p_height = pointsize * t->v_tic;
  372.     p_width = pointsize * t->h_tic;
  373.     if (key_swidth >= 0)
  374.     key_sample_width = key_swidth * (t->h_char) + pointsize * (t->h_tic);
  375.     else
  376.     key_sample_width = 0;
  377.     key_entry_height = pointsize * (t->v_tic) * 1.25 * key_vert_factor;
  378.     if (key_entry_height < (t->v_char)) {
  379.     /* is this reasonable ? */
  380.     key_entry_height = (t->v_char) * key_vert_factor;
  381.     }
  382.  
  383.     /* count max_len key and number keys (plot-titles and contour labels) with len > 0 */
  384.     max_ptitl_len = find_maxl_keys3d(plots, count, &ptitl_cnt);
  385.     if ((ytlen = label_width(key_title, &ktitle_lines)) > max_ptitl_len)
  386.     max_ptitl_len = ytlen;
  387.     key_col_wth = (max_ptitl_len + 4) * (t->h_char) + key_sample_width;
  388.  
  389.     /* luecken@udel.edu modifications
  390.        sizes the plot to take up more of available resolution */
  391.     if (lmargin >= 0)
  392.     xleft = (t->h_char) * lmargin;
  393.     else
  394.     xleft = (t->h_char) * 2 + (t->h_tic);
  395.     xright = (scaling ? 1 : xsize) * (t->xmax) - (t->h_char) * 2 - (t->h_tic);
  396.     key_rows = ptitl_cnt;
  397.     key_cols = 1;
  398.     if (key == -1 && key_vpos == TUNDER) {
  399.       if (ptitl_cnt > 0) {
  400.     /* calculate max no cols, limited by label-length */
  401.     key_cols = (int) (xright - xleft) / ((max_ptitl_len + 4) * (t->h_char) + key_sample_width);
  402.     /* HBB 991019: fix division by zero problem */
  403.     if (key_cols == 0)
  404.         key_cols = 1;
  405.     key_rows = (int) (ptitl_cnt / key_cols) + ((ptitl_cnt % key_cols) > 0);
  406.     /* now calculate actual no cols depending on no rows */
  407.     key_cols = (int) (ptitl_cnt / key_rows) + ((ptitl_cnt % key_rows) > 0);
  408.     key_col_wth = (int) (xright - xleft) / key_cols;
  409.     /* key_rows += ktitle_lines; - messes up key - div */
  410.       } else {
  411.     key_rows = key_cols = key_col_wth = 0;
  412.       }
  413.     }
  414.     /* this should also consider the view and number of lines in
  415.      * xformat || yformat || xlabel || ylabel */
  416.  
  417.     /* an absolute 1, with no terminal-dependent scaling ? */
  418.     ybot = (t->v_char) * 2.5 + 1;
  419.     if (key_rows && key_vpos == TUNDER)
  420.     ybot += key_rows * key_entry_height + ktitle_lines * t->v_char;
  421.  
  422.     if (strlen(title.text)) {
  423.     titlelin++;
  424.     for (i = 0; i < strlen(title.text); i++) {
  425.         if (title.text[i] == '\\')
  426.         titlelin++;
  427.     }
  428.     }
  429.     ytop = (scaling ? 1 : ysize) * (t->ymax) - (t->v_char) * (titlelin + 1.5) - 1;
  430.     if (key == -1 && key_vpos != TUNDER) {
  431.     /* calculate max no rows, limited be ytop-ybot */
  432.     i = (int) (ytop - ybot) / (t->v_char) - 1 - ktitle_lines;
  433.     if (ptitl_cnt > i) {
  434.         key_cols = (int) (ptitl_cnt / i) + ((ptitl_cnt % i) > 0);
  435.         /* now calculate actual no rows depending on no cols */
  436.         key_rows = (int) (ptitl_cnt / key_cols) + ((ptitl_cnt % key_cols) > 0);
  437.     }
  438.     key_rows += ktitle_lines;
  439.     }
  440.     if (key_hpos == TOUT) {
  441.     xright -= key_col_wth * (key_cols - 1) + key_col_wth - 2 * (t->h_char);
  442.     }
  443.     xleft += t->xmax * xoffset;
  444.     xright += t->xmax * xoffset;
  445.     ytop += t->ymax * yoffset;
  446.     ybot += t->ymax * yoffset;
  447.     xmiddle = (xright + xleft) / 2;
  448.     ymiddle = (ytop + ybot) / 2;
  449.     /* HBB 980308: sigh... another 16bit glitch: on term's with more than
  450.      * 8000 pixels in either direction, these calculations produce garbage
  451.      * results if done in (16bit) ints */
  452.     xscaler = ((xright - xleft) * 4L) / 7L;              /* HBB: Magic number alert! */
  453.     yscaler = ((ytop - ybot) * 4L) / 7L;
  454.  
  455. }
  456.  
  457. #if 0
  458. /* not used ; anyway, should be done using bitshifts and squares,
  459.  * rather than iteratively
  460.  */
  461. static double dbl_raise(x, y)
  462. double x;
  463. int y;
  464. {
  465.     register int i = ABS(y);
  466.     double val = 1.0;
  467.     while (--i >= 0)
  468.     val *= x;
  469.     if (y < 0)
  470.     return (1.0 / val);
  471.     return (val);
  472. }
  473. #endif
  474.  
  475. /* we precalculate features of the key, to save lots of nested
  476.  * ifs in code - x,y = user supplied or computed position of key
  477.  * taken to be inner edge of a line sample
  478.  */
  479. static int key_sample_left;    /* offset from x for left of line sample */
  480. static int key_sample_right;    /* offset from x for right of line sample */
  481. static int key_point_offset;    /* offset from x for point sample */
  482. static int key_text_left;    /* offset from x for left-justified text */
  483. static int key_text_right;    /* offset from x for right-justified text */
  484. static int key_size_left;    /* distance from x to left edge of box */
  485. static int key_size_right;    /* distance from x to right edge of box */
  486.  
  487. void do_3dplot(plots, pcount)
  488. struct surface_points *plots;
  489. int pcount;            /* count of plots in linked list */
  490. {
  491.     struct termentry *t = term;
  492.     int surface;
  493.     struct surface_points *this_plot = NULL;
  494.     unsigned int xl, yl;
  495.     int linetypeOffset = 0;
  496.     /* double ztemp, temp; unused */
  497.     struct text_label *this_label;
  498.     struct arrow_def *this_arrow;
  499.     TBOOLEAN scaling;
  500.     transform_matrix mat;
  501.     int key_count;
  502.     char *s, *e;
  503.  
  504.     /* Initiate transformation matrix using the global view variables. */
  505.     mat_rot_z(surface_rot_z, trans_mat);
  506.     mat_rot_x(surface_rot_x, mat);
  507.     mat_mult(trans_mat, trans_mat, mat);
  508.     mat_scale(surface_scale / 2.0, surface_scale / 2.0, surface_scale / 2.0, mat);
  509.     mat_mult(trans_mat, trans_mat, mat);
  510.  
  511. #if 0
  512.     /* HBB 19990609: this is *not* the way to implement 'set view' <z_scale> */
  513.     /* modify min_z/max_z so it will zscale properly. */
  514.     ztemp = (z_max3d - z_min3d) / (2.0 * surface_zscale);
  515.     temp = (z_max3d + z_min3d) / 2.0;
  516.     z_min3d = temp - ztemp;
  517.     z_max3d = temp + ztemp;
  518. #endif /* 0 */
  519.  
  520.     /* The extrema need to be set even when a surface is not being
  521.      * drawn.   Without this, gnuplot used to assume that the X and
  522.      * Y axis started at zero.   -RKC
  523.      */
  524.  
  525.     if (polar)
  526.     graph_error("Cannot splot in polar coordinate system.");
  527.  
  528.     /* done in plot3d.c
  529.      *    if (z_min3d == VERYLARGE || z_max3d == -VERYLARGE ||
  530.      *      x_min3d == VERYLARGE || x_max3d == -VERYLARGE ||
  531.      *      y_min3d == VERYLARGE || y_max3d == -VERYLARGE)
  532.      *      graph_error("all points undefined!");
  533.      */
  534.  
  535.     /* If we are to draw the bottom grid make sure zmin is updated properly. */
  536.     if (xtics || ytics || work_grid.l_type) {
  537.     base_z = z_min3d - (z_max3d - z_min3d) * ticslevel;
  538.     if (ticslevel >= 0)
  539.         floor_z = base_z;
  540.     else
  541.         floor_z = z_min3d;
  542.  
  543.     if (ticslevel < -1)
  544.         ceiling_z = base_z;
  545.     else
  546.         ceiling_z = z_max3d;
  547.     } else {
  548.     floor_z = base_z = z_min3d;
  549.     ceiling_z = z_max3d;
  550.     }
  551.  
  552.     /*  see comment accompanying similar tests of x_min/x_max and y_min/y_max
  553.      *  in graphics.c:do_plot(), for history/rationale of these tests */
  554.     if (x_min3d == x_max3d)
  555.     graph_error("x_min3d should not equal x_max3d!");
  556.     if (y_min3d == y_max3d)
  557.     graph_error("y_min3d should not equal y_max3d!");
  558.     if (z_min3d == z_max3d)
  559.     graph_error("z_min3d should not equal z_max3d!");
  560.  
  561. #ifndef LITE
  562.     if (hidden3d) {
  563.     struct surface_points *plot;
  564.     int p = 0;
  565.     /* Verify data is hidden line removable - grid based. */
  566.     for (plot = plots; ++p <= pcount; plot = plot->next_sp) {
  567.         if (plot->plot_type == DATA3D && !plot->has_grid_topology) {
  568.         fprintf(stderr, "Notice: Cannot remove hidden lines from non grid data\n");
  569.         return;
  570.         }
  571.     }
  572.     }
  573. #endif /* not LITE */
  574.  
  575.     term_start_plot();
  576.  
  577.     screen_ok = FALSE;
  578.     scaling = (*t->scale) (xsize, ysize);
  579.  
  580.     /* now compute boundary for plot (xleft, xright, ytop, ybot) */
  581.     boundary3d(scaling, plots, pcount);
  582.  
  583.     /* SCALE FACTORS */
  584.     zscale3d = 2.0 / (ceiling_z - floor_z) * surface_zscale;
  585.     yscale3d = 2.0 / (y_max3d - y_min3d);
  586.     xscale3d = 2.0 / (x_max3d - x_min3d);
  587.  
  588.     term_apply_lp_properties(&border_lp);    /* border linetype */
  589.  
  590.     /* PLACE TITLE */
  591.     if (*title.text != 0) {
  592.     write_multiline((unsigned int) ((xleft + xright) / 2 + title.xoffset * t->h_char),
  593.             (unsigned int) (ytop + (titlelin + title.yoffset) * (t->h_char)),
  594.             title.text, CENTRE, JUST_TOP, 0, title.font);
  595.     }
  596.     /* PLACE TIMEDATE */
  597.     if (*timelabel.text) {
  598.     char str[MAX_LINE_LEN+1];
  599.     time_t now;
  600.     unsigned int x = t->v_char + timelabel.xoffset * t->h_char;
  601.     unsigned int y = timelabel_bottom ?
  602.     yoffset * ymax + (timelabel.yoffset + 1) * t->v_char :
  603.     ytop + (timelabel.yoffset - 1) * t->v_char;
  604.  
  605.     time(&now);
  606.     strftime(str, MAX_LINE_LEN, timelabel.text, localtime(&now));
  607.  
  608.     if (timelabel_rotate && (*t->text_angle) (1)) {
  609.         if (timelabel_bottom)
  610.         write_multiline(x, y, str, LEFT, JUST_TOP, 1, timelabel.font);
  611.         else
  612.         write_multiline(x, y, str, RIGHT, JUST_TOP, 1, timelabel.font);
  613.  
  614.         (*t->text_angle) (0);
  615.     } else {
  616.         if (timelabel_bottom)
  617.         write_multiline(x, y, str, LEFT, JUST_BOT, 0, timelabel.font);
  618.         else
  619.         write_multiline(x, y, str, LEFT, JUST_TOP, 0, timelabel.font);
  620.     }
  621.     }
  622.     /* PLACE LABELS */
  623.     for (this_label = first_label; this_label != NULL;
  624.      this_label = this_label->next) {
  625.     unsigned int x, y;
  626.  
  627.  
  628.     map_position(&this_label->place, &x, &y, "label");
  629.     if (this_label->rotate && (*t->text_angle) (1)) {
  630.         write_multiline(x, y, this_label->text, this_label->pos, CENTRE, 1, this_label->font);
  631.         (*t->text_angle) (0);
  632.     } else {
  633.         write_multiline(x, y, this_label->text, this_label->pos, CENTRE, 0, this_label->font);
  634.     }
  635.     }
  636.  
  637.     /* PLACE ARROWS */
  638.     for (this_arrow = first_arrow; this_arrow != NULL;
  639.      this_arrow = this_arrow->next) {
  640.     unsigned int sx, sy, ex, ey;
  641.  
  642.     map_position(&this_arrow->start, &sx, &sy, "arrow");
  643.     map_position(&this_arrow->end, &ex, &ey, "arrow");
  644.     term_apply_lp_properties(&(this_arrow->lp_properties));
  645.     (*t->arrow) (sx, sy, ex, ey, this_arrow->head);
  646.     }
  647.  
  648. #ifndef LITE
  649.     if (hidden3d && draw_surface) {
  650.     init_hidden_line_removal();
  651.     reset_hidden_line_removal();
  652.     hidden_active = TRUE;
  653.     }
  654. #endif /* not LITE */
  655.  
  656.     /* WORK OUT KEY SETTINGS AND DO KEY TITLE / BOX */
  657.  
  658.     if (key_reverse) {
  659.     key_sample_left = -key_sample_width;
  660.     key_sample_right = 0;
  661.     key_text_left = t->h_char;
  662.     key_text_right = (t->h_char) * (max_ptitl_len + 1);
  663.     key_size_right = (t->h_char) * (max_ptitl_len + 2 + key_width_fix);
  664.     key_size_left = (t->h_char) + key_sample_width;
  665.     } else {
  666.     key_sample_left = 0;
  667.     key_sample_right = key_sample_width;
  668.     key_text_left = -(int) ((t->h_char) * (max_ptitl_len + 1));
  669.     key_text_right = -(int) (t->h_char);
  670.     key_size_left = (t->h_char) * (max_ptitl_len + 2 + key_width_fix);
  671.     key_size_right = (t->h_char) + key_sample_width;
  672.     }
  673.     key_point_offset = (key_sample_left + key_sample_right) / 2;
  674.  
  675.     if (key == -1) {
  676.     if (key_vpos == TUNDER) {
  677. #if 0
  678.         yl = yoffset * t->ymax + (key_rows) * key_entry_height + (ktitle_lines + 2) * t->v_char;
  679.         xl = max_ptitl_len * 1000 / (key_sample_width / (t->h_char) + max_ptitl_len + 2);
  680.         xl *= (xright - xleft) / key_cols;
  681.         xl /= 1000;
  682.         xl += xleft;
  683. #else
  684.         /* HBB 19990608: why calculate these again? boundary3d has already 
  685.          * done it... */
  686.         if (ptitl_cnt > 0) {
  687.         /* maximise no cols, limited by label-length */
  688.         key_cols = (int) (xright - xleft) / key_col_wth;
  689.         key_rows = (int) (ptitl_cnt + key_cols - 1) / key_cols;
  690.         /* now calculate actual no cols depending on no rows */
  691.         key_cols = (int) (ptitl_cnt + key_rows - 1) / key_rows;
  692.         key_col_wth = (int) (xright - xleft) / key_cols;
  693.         /* we divide into columns, then centre in column by considering
  694.          * ratio of key_left_size to key_right_size
  695.          * key_size_left/(key_size_left+key_size_right) * (xright-xleft)/key_cols
  696.          * do one integer division to maximise accuracy (hope we dont
  697.          * overflow !)
  698.          */
  699.         xl = xleft + ((xright - xleft) * key_size_left) / (key_cols * (key_size_left + key_size_right));
  700.         yl = yoffset * t->ymax + (key_rows) * key_entry_height + (ktitle_lines + 2) * t->v_char;
  701.         }
  702. #endif
  703.     } else {
  704.         if (key_vpos == TTOP) {
  705.         yl = ytop - (t->v_tic) - t->v_char;
  706.         } else {
  707.         yl = ybot + (t->v_tic) + key_entry_height * key_rows + ktitle_lines * t->v_char;
  708.         }
  709.         if (key_hpos == TOUT) {
  710.         /* keys outside plot border (right) */
  711.         xl = xright + (t->h_tic) + key_size_left;
  712.         } else if (key_hpos == TLEFT) {
  713.         xl = xleft + (t->h_tic) + key_size_left;
  714.         } else {
  715.         xl = xright - key_size_right - key_col_wth * (key_cols - 1);
  716.         }
  717.     }
  718.     yl_ref = yl - ktitle_lines * (t->v_char);
  719.     }
  720.     if (key == 1) {
  721.     map_position(&key_user_pos, &xl, &yl, "key");
  722.     }
  723.     if (key && key_box.l_type > -3) {
  724.     int yt = yl;
  725.     int yb = yl - key_entry_height * (key_rows - ktitle_lines) - ktitle_lines * t->v_char;
  726.     int key_xr = xl + key_col_wth * (key_cols - 1) + key_size_right;
  727.     /* key_rows seems to contain title at this point ??? */
  728.     term_apply_lp_properties(&key_box);
  729.     (*t->move) (xl - key_size_left, yb);
  730.     (*t->vector) (xl - key_size_left, yt);
  731.     (*t->vector) (key_xr, yt);
  732.     (*t->vector) (key_xr, yb);
  733.     (*t->vector) (xl - key_size_left, yb);
  734.  
  735.     /* draw a horizontal line between key title and first entry  JFi */
  736.     (*t->move) (xl - key_size_left, yt - (ktitle_lines) * t->v_char);
  737.     (*t->vector) (xl + key_size_right, yt - (ktitle_lines) * t->v_char);
  738.     }
  739.     /* DRAW SURFACES AND CONTOURS */
  740.  
  741. #ifndef LITE
  742.     if (hidden3d && draw_surface)
  743.     plot3d_hidden(plots, pcount);
  744. #endif /* not LITE */
  745.  
  746.     /* KEY TITLE */
  747.     if (key != 0 && strlen(key_title)) {
  748.     char *ss = gp_alloc(strlen(key_title) + 2, "tmp string ss");
  749.     strcpy(ss, key_title);
  750.     strcat(ss, "\n");
  751.     s = ss;
  752.     yl -= t->v_char / 2;
  753.     while ((e = (char *) strchr(s, '\n')) != NULL) {
  754.         *e = '\0';
  755.         if (key_just == JLEFT) {
  756.         (*t->justify_text) (LEFT);
  757.         (*t->put_text) (xl + key_text_left, yl, s);
  758.         } else {
  759.         if ((*t->justify_text) (RIGHT)) {
  760.             (*t->put_text) (xl + key_text_right,
  761.                     yl, s);
  762.         } else {
  763.             int x = xl + key_text_right - (t->h_char) * strlen(s);
  764.             if (inrange(x, xleft, xright))
  765.             (*t->put_text) (x, yl, s);
  766.         }
  767.         }
  768.         s = ++e;
  769.         yl -= t->v_char;
  770.     }
  771.     yl += t->v_char / 2;
  772.     free(ss);
  773.     }
  774.     key_count = 0;
  775.     yl_ref = yl -= key_entry_height / 2;    /* centralise the keys */
  776.  
  777. #define NEXT_KEY_LINE() \
  778.  if ( ++key_count >= key_rows ) { \
  779.    yl = yl_ref; xl += key_col_wth; key_count = 0; \
  780.  } else \
  781.    yl -= key_entry_height
  782.  
  783.     this_plot = plots;
  784.     for (surface = 0;
  785.      surface < pcount;
  786.      this_plot = this_plot->next_sp, surface++) {
  787.  
  788. #ifndef LITE
  789.     if (hidden3d)
  790.         hidden_no_update = FALSE;
  791. #endif /* not LITE */
  792.  
  793.     if (draw_surface) {
  794.         int lkey = (key != 0 && this_plot->title && this_plot->title[0]);
  795.         term_apply_lp_properties(&(this_plot->lp_properties));
  796.  
  797. #ifndef LITE
  798.         if (hidden3d) {
  799.         hidden_line_type_above = this_plot->lp_properties.l_type;
  800.         hidden_line_type_below = this_plot->lp_properties.l_type + 1;
  801.         }
  802. #endif /* not LITE */
  803.  
  804.         if (lkey) {
  805.         key_text(xl, yl, this_plot->title);
  806.         }
  807.         switch (this_plot->plot_style) {
  808.         case BOXES:    /* can't do boxes in 3d yet so use impulses */
  809.         case IMPULSES:{
  810.             if (lkey) {
  811.             key_sample_line(xl, yl);
  812.             }
  813.             if (!(hidden3d && draw_surface))
  814.             plot3d_impulses(this_plot);
  815.             break;
  816.         }
  817.         case STEPS:    /* HBB: I think these should be here */
  818.         case FSTEPS:
  819.         case HISTEPS:
  820.         case LINES:{
  821.             if (lkey) {
  822.             key_sample_line(xl, yl);
  823.             }
  824.             if (!(hidden3d && draw_surface))
  825.             plot3d_lines(this_plot);
  826.             break;
  827.         }
  828.         case YERRORBARS:    /* ignored; treat like points */
  829.         case XERRORBARS:    /* ignored; treat like points */
  830.         case XYERRORBARS:    /* ignored; treat like points */
  831.         case BOXXYERROR:    /* HBB: ignore these as well */
  832.         case BOXERROR:
  833.         case CANDLESTICKS:    /* HBB: dito */
  834.         case FINANCEBARS:
  835.         case VECTOR:
  836.         case POINTSTYLE:
  837.         if (lkey && !clip_point(xl + key_point_offset, yl)) {
  838.             key_sample_point(xl, yl, this_plot->lp_properties.p_type);
  839.         }
  840.         if (!(hidden3d && draw_surface))
  841.             plot3d_points(this_plot);
  842.         break;
  843.  
  844.         case LINESPOINTS:
  845.         /* put lines */
  846.         if (lkey)
  847.             key_sample_line(xl, yl);
  848.  
  849.         if (!(hidden3d && draw_surface))
  850.             plot3d_lines(this_plot);
  851.  
  852.         /* put points */
  853.         if (lkey && !clip_point(xl + key_point_offset, yl))
  854.             key_sample_point(xl, yl, this_plot->lp_properties.p_type);
  855.  
  856.         if (!(hidden3d && draw_surface))
  857.             plot3d_points(this_plot);
  858.  
  859.         break;
  860.  
  861.         case DOTS:
  862.         if (lkey) {
  863.             if (key == 1) {
  864.             if (!clip_point(xl + key_point_offset, yl))
  865.                 (*t->point) (xl + key_point_offset, yl, -1);
  866.             } else {
  867.             (*t->point) (xl + key_point_offset, yl, -1);
  868.             /* (*t->point)(xl+2*(t->h_char),yl, -1); */
  869.             }
  870.         }
  871.         if (!(hidden3d && draw_surface))
  872.             plot3d_dots(this_plot);
  873.  
  874.         break;
  875.  
  876.  
  877.         }            /* switch(plot-style) */
  878.  
  879.         /* move key on a line */
  880.         if (lkey) {
  881.         NEXT_KEY_LINE();
  882.         }
  883.     }            /* draw_surface */
  884.  
  885. #ifndef LITE 
  886.     if (hidden3d) {
  887.         hidden_no_update = TRUE;
  888.         hidden_line_type_above = this_plot->lp_properties.l_type + (hidden3d ? 2 : 1);
  889.         hidden_line_type_below = this_plot->lp_properties.l_type + (hidden3d ? 2 : 1);
  890.     }
  891. #endif /* not LITE */
  892.  
  893.     if (draw_contour && this_plot->contours != NULL) {
  894.         struct gnuplot_contours *cntrs = this_plot->contours;
  895.  
  896.         term_apply_lp_properties(&(this_plot->lp_properties));
  897.         (*t->linetype) (this_plot->lp_properties.l_type + (hidden3d ? 2 : 1));
  898.  
  899.         if (key != 0 && this_plot->title && this_plot->title[0]
  900.         && !draw_surface && !label_contours) {
  901.         /* unlabelled contours but no surface : put key entry in now */
  902.         key_text(xl, yl, this_plot->title);
  903.  
  904.         switch (this_plot->plot_style) {
  905.         case IMPULSES:
  906.         case LINES:
  907.         case BOXES:    /* HBB: I think these should be here... */
  908.         case STEPS:
  909.         case FSTEPS:
  910.         case HISTEPS:
  911.             key_sample_line(xl, yl);
  912.             break;
  913.         case YERRORBARS:    /* ignored; treat like points */
  914.         case XERRORBARS:    /* ignored; treat like points */
  915.         case XYERRORBARS:    /* ignored; treat like points */
  916.         case BOXERROR:    /* HBB: ignore these as well */
  917.         case BOXXYERROR:
  918.         case CANDLESTICKS:    /* HBB: dito */
  919.         case FINANCEBARS:
  920.         case VECTOR:
  921.         case POINTSTYLE:
  922.             key_sample_point(xl, yl, this_plot->lp_properties.p_type);
  923.             break;
  924.         case LINESPOINTS:
  925.             key_sample_line(xl, yl);
  926.             break;
  927.         case DOTS:
  928.             key_sample_point(xl, yl, -1);
  929.             break;
  930.         }
  931.         NEXT_KEY_LINE();
  932.         }
  933.         linetypeOffset = this_plot->lp_properties.l_type + (hidden3d ? 2 : 1);
  934.         while (cntrs) {
  935.         if (label_contours && cntrs->isNewLevel) {
  936.             (*t->linetype) (linetypeOffset++);
  937.             if (key) {
  938.  
  939. #ifndef LITE
  940.             if (hidden3d)
  941.                 hidden_line_type_below = hidden_line_type_above = linetypeOffset - 1;
  942. #endif /* not LITE */
  943.  
  944.             key_text(xl, yl, cntrs->label);
  945.  
  946.             switch (this_plot->plot_style) {
  947.             case IMPULSES:
  948.             case LINES:
  949.             case LINESPOINTS:
  950.             case BOXES:    /* HBB: these should be treated as well... */
  951.             case STEPS:
  952.             case FSTEPS:
  953.             case HISTEPS:
  954.                 key_sample_line(xl, yl);
  955.                 break;
  956.             case YERRORBARS:    /* ignored; treat like points */
  957.             case XERRORBARS:    /* ignored; treat like points */
  958.             case XYERRORBARS:    /* ignored; treat like points */
  959.             case BOXERROR:        /* HBB: treat these likewise */
  960.             case BOXXYERROR:
  961.             case CANDLESTICKS:    /* HBB: dito */
  962.             case FINANCEBARS:
  963.             case VECTOR:
  964.             case POINTSTYLE:
  965.                 key_sample_point(xl, yl, this_plot->lp_properties.p_type);
  966.                 break;
  967.             case DOTS:
  968.                 key_sample_point(xl, yl, -1);
  969.                 break;
  970.             }    /* switch */
  971.  
  972.             NEXT_KEY_LINE();
  973.  
  974.             }        /* key */
  975.         }        /* label_contours */
  976.         /* now draw the contour */
  977.         switch (this_plot->plot_style) {
  978.         case IMPULSES:
  979.         case BOXES:    /* HBB: this should also be treated somehow */
  980.             cntr3d_impulses(cntrs, this_plot);
  981.             break;
  982.         case LINES:
  983.         case STEPS:    /* HBB: these should also be handled, I think */
  984.         case FSTEPS:
  985.         case HISTEPS:
  986.             cntr3d_lines(cntrs);
  987.             break;
  988.         case YERRORBARS:    /* ignored; treat like points */
  989.         case XERRORBARS:    /* ignored; treat like points */
  990.         case XYERRORBARS:    /* ignored; treat like points */
  991.         case BOXERROR:    /* HBB: ignore these too... */
  992.         case BOXXYERROR:
  993.         case CANDLESTICKS:    /* HBB: dito */
  994.         case FINANCEBARS:
  995.         case VECTOR:
  996.         case POINTSTYLE:
  997.             cntr3d_points(cntrs, this_plot);
  998.             break;
  999.         case LINESPOINTS:
  1000.             cntr3d_lines(cntrs);
  1001.             cntr3d_points(cntrs, this_plot);
  1002.             break;
  1003.         case DOTS:
  1004.             cntr3d_dots(cntrs);
  1005.             break;
  1006.         }        /*switch */
  1007.  
  1008.         cntrs = cntrs->next;
  1009.         }            /* loop over contours */
  1010.     }            /* draw contours */
  1011.     }                /* loop over surfaces */
  1012.  
  1013.     draw_bottom_grid(plots, pcount);
  1014.  
  1015.     term_end_plot();
  1016.  
  1017. #ifndef LITE
  1018.     if (hidden3d && draw_surface) {
  1019.     term_hidden_line_removal();
  1020.     hidden_active = FALSE;
  1021.     }
  1022. #endif /* not LITE */
  1023.  
  1024. }
  1025.  
  1026. /* plot3d_impulses:
  1027.  * Plot the surfaces in IMPULSES style
  1028.  */
  1029. static void plot3d_impulses(plot)
  1030. struct surface_points *plot;
  1031. {
  1032.     int i;            /* point index */
  1033.     unsigned int x, y, x0, y0;    /* point in terminal coordinates */
  1034.     struct iso_curve *icrvs = plot->iso_crvs;
  1035.  
  1036.     while (icrvs) {
  1037.     struct coordinate GPHUGE *points = icrvs->points;
  1038.  
  1039.     for (i = 0; i < icrvs->p_count; i++) {0h ”èH9¤ints[i].type) {
  1040.         case INRANGE:
  1041.         {
  1042.             map3d_xy(points[i].x, points[i].y, points[i].z, &x, &y);
  1043.  
  1044.             if (inrange(0.0, min3d_z, max3d_z)) {
  1045.             map3d_xy(points[i].x, points[i].y, 0.0, &x0, &y0);
  1046.             } else if (inrange(min3d_z, 0.0, points[i].z)) {
  1047.             map3d_xy(points[i].x, points[i].y, min3d_z, &x0, &y0);
  1048.             } else {
  1049.             map3d_xy(points[i].x, points[i].y, max3d_z, &x0, &y0);
  1050.             }
  1051.  
  1052.             clip_move(x0, y0);
  1053.             clip_vector(x, y);
  1054.  
  1055.             break;
  1056.         }
  1057.         case OUTRANGE:
  1058.         {
  1059.             if (!inrange(points[i].x, x_min3d, x_max3d) ||
  1060.             !inrange(points[i].y, y_min3d, y_max3d))
  1061.             break;
  1062.  
  1063.             if (inrange(0.0, min3d_z, max3d_z)) {
  1064.             /* zero point is INRANGE */
  1065.             map3d_xy(points[i].x, points[i].y, 0.0, &x0, &y0);
  1066.  
  1067.             /* must cross z = min3d_z or max3d_z limits */
  1068.             if (inrange(min3d_z, 0.0, points[i].z) &&
  1069.                 min3d_z != 0.0 && min3d_z != points[i].z) {
  1070.                 map3d_xy(points[i].x, points[i].y, min3d_z, &x, &y);
  1071.             } else {
  1072.                 map3d_xy(points[i].x, points[i].y, max3d_z, &x, &y);
  1073.             }
  1074.             } else {
  1075.             /* zero point is also OUTRANGE */
  1076.             if (inrange(min3d_z, 0.0, points[i].z) &&
  1077.                 inrange(max3d_z, 0.0, points[i].z)) {
  1078.                 /* crosses z = min3d_z or max3d_z limits */
  1079.                 map3d_xy(points[i].x, points[i].y, max3d_z, &x, &y);
  1080.                 map3d_xy(points[i].x, points[i].y, min3d_z, &x0, &y0);
  1081.             } else {
  1082.                 /* doesn't cross z = min3d_z or max3d_z limits */
  1083.                 break;
  1084.             }
  1085.             }
  1086.  
  1087.             clip_move(x0, y0);
  1088.             clip_vector(x, y);
  1089.  
  1090.             break;
  1091.         }
  1092.         default:        /* just a safety */
  1093.         case UNDEFINED:{
  1094.             break;
  1095.         }
  1096.         }
  1097.     }
  1098.  
  1099.     icrvs = icrvs->next;
  1100.     }
  1101. }
  1102.  
  1103. /* plot3d_lines:
  1104.  * Plot the surfaces in LINES style
  1105.  */
  1106. /* We want to always draw the lines in the same direction, otherwise when
  1107.    we draw an adjacent box we might get the line drawn a little differently
  1108.    and we get splotches.  */
  1109.  
  1110. static void plot3d_lines(plot)
  1111. struct surface_points *plot;
  1112. {
  1113.     int i;
  1114.     unsigned int x, y, x0, y0;    /* point in terminal coordinates */
  1115.     double clip_x, clip_y, clip_z;
  1116.     struct iso_curve *icrvs = plot->iso_crvs;
  1117.     struct coordinate GPHUGE *points;
  1118.     enum coord_type prev = UNDEFINED;
  1119.     double lx[2], ly[2], lz[2];    /* two edge points */
  1120.  
  1121. #ifndef LITE
  1122. /* These are handled elsewhere.  */
  1123.     if (plot->has_grid_topology && hidden3d)
  1124.     return;
  1125. #endif /* not LITE */
  1126.  
  1127.     while (icrvs) {
  1128.     prev = UNDEFINED;    /* type of previous plot */
  1129.  
  1130.     for (i = 0, points = icrvs->points; i < icrvs->p_count; i++) {
  1131.         switch (points[i].type) {
  1132.         case INRANGE:{
  1133.             map3d_xy(points[i].x, points[i].y, points[i].z, &x, &y);
  1134.  
  1135.             if (prev == INRANGE) {
  1136.             clip_vector(x, y);
  1137.             } else {
  1138.             if (prev == OUTRANGE) {
  1139.                 /* from outrange to inrange */
  1140.                 if (!clip_lines1) {
  1141.                 clip_move(x, y);
  1142.                 } else {
  1143.                 /*
  1144.                  * Calculate intersection point and draw
  1145.                  * vector from there
  1146.                  */
  1147.                 edge3d_intersect(points, i, &clip_x, &clip_y, &clip_z);
  1148.  
  1149.                 map3d_xy(clip_x, clip_y, clip_z, &x0, &y0);
  1150.  
  1151.                 clip_move(x0, y0);
  1152.                 clip_vector(x, y);
  1153.                 }
  1154.             } else {
  1155.                 clip_move(x, y);
  1156.             }
  1157.             }
  1158.  
  1159.             break;
  1160.         }
  1161.         case OUTRANGE:{
  1162.             if (prev == INRANGE) {
  1163.             /* from inrange to outrange */
  1164.             if (clip_lines1) {
  1165.                 /*
  1166.                  * Calculate intersection point and draw
  1167.                  * vector to it
  1168.                  */
  1169.  
  1170.                 edge3d_intersect(points, i, &clip_x, &clip_y, &clip_z);
  1171.  
  1172.                 map3d_xy(clip_x, clip_y, clip_z, &x0, &y0);
  1173.  
  1174.                 clip_vector(x0, y0);
  1175.             }
  1176.             } else if (prev == OUTRANGE) {
  1177.             /* from outrange to outrange */
  1178.             if (clip_lines2) {
  1179.                 /*
  1180.                  * Calculate the two 3D intersection points
  1181.                  * if present
  1182.                  */
  1183.                 if (two_edge3d_intersect(points, i, lx, ly, lz)) {
  1184.  
  1185.                 map3d_xy(lx[0], ly[0], lz[0], &x, &y);
  1186.  
  1187.                 map3d_xy(lx[1], ly[1], lz[1], &x0, &y0);
  1188.  
  1189.                 clip_move(x, y);
  1190.                 clip_vector(x0, y0);
  1191.                 }
  1192.             }
  1193.             }
  1194.             break;
  1195.         }
  1196.         case UNDEFINED:{
  1197.             break;
  1198.         default:
  1199.             graph_error("Unknown point type in plot3d_lines");
  1200.         }
  1201.         }
  1202.  
  1203.         prev = points[i].type;
  1204.     }
  1205.  
  1206.     icrvs = icrvs->next;
  1207.     }
  1208. }
  1209.  
  1210. /* plot3d_points:
  1211.  * Plot the surfaces in POINTSTYLE style
  1212.  */
  1213. static void plot3d_points(plot)
  1214. struct surface_points *plot;
  1215. {
  1216.     int i;
  1217.     unsigned int x, y;
  1218.     struct termentry *t = term;
  1219.     struct iso_curve *icrvs = plot->iso_crvs;
  1220.  
  1221.     while (icrvs) {
  1222.     struct coordinate GPHUGE *points = icrvs->points;
  1223.  
  1224.     for (i = 0; i < icrvs->p_count; i++) {
  1225.         if (points[i].type == INRANGE) {
  1226.         map3d_xy(points[i].x, points[i].y, points[i].z, &x, &y);
  1227.  
  1228.         if (!clip_point(x, y))
  1229.             (*t->point) (x, y, plot->lp_properties.p_type);
  1230.         }
  1231.     }
  1232.  
  1233.     icrvs = icrvs->next;
  1234.     }
  1235. }
  1236.  
  1237. /* plot3d_dots:
  1238.  * Plot the surfaces in DOTS style
  1239.  */
  1240. static void plot3d_dots(plot)
  1241. struct surface_points *plot;
  1242. {
  1243.     int i;
  1244.     struct termentry *t = term;
  1245.     struct iso_curve *icrvs = plot->iso_crvs;
  1246.  
  1247.     while (icrvs) {
  1248.     struct coordinate GPHUGE *points = icrvs->points;
  1249.  
  1250.     for (i = 0; i < icrvs->p_count; i++) {
  1251.         if (points[i].type == INRANGE) {
  1252.         unsigned int x, y;
  1253.         map3d_xy(points[i].x, points[i].y, points[i].z, &x, &y);
  1254.  
  1255.         if (!clip_point(x, y))
  1256.             (*t->point) (x, y, -1);
  1257.         }
  1258.     }
  1259.  
  1260.     icrvs = icrvs->next;
  1261.     }
  1262. }
  1263.  
  1264. /* cntr3d_impulses:
  1265.  * Plot a surface contour in IMPULSES style
  1266.  */
  1267. static void cntr3d_impulses(cntr, plot)
  1268. struct gnuplot_contours *cntr;
  1269. struct surface_points *plot;
  1270. {
  1271.     int i;            /* point index */
  1272.     unsigned int x, y, x0, y0;    /* point in terminal coordinates */
  1273.  
  1274.     if (draw_contour & CONTOUR_SRF) {
  1275.     for (i = 0; i < cntr->num_pts; i++) {
  1276.         map3d_xy(cntr->coords[i].x, cntr->coords[i].y, cntr->coords[i].z,
  1277.              &x, &y);
  1278.         map3d_xy(cntr->coords[i].x, cntr->coords[i].y, base_z,
  1279.              &x0, &y0);
  1280.  
  1281.         clip_move(x0, y0);
  1282.         clip_vector(x, y);
  1283.     }
  1284.     } else {
  1285.     /* Must be on base grid, so do points. */
  1286.     cntr3d_points(cntr, plot);
  1287.     }
  1288. }
  1289.  
  1290. /* cntr3d_lines:
  1291.  * Plot a surface contour in LINES style
  1292.  */
  1293. static void cntr3d_lines(cntr)
  1294. struct gnuplot_contours *cntr;
  1295. {
  1296.     int i;            /* point index */
  1297.     unsigned int x, y;        /* point in terminal coordinates */
  1298.  
  1299.     if (draw_contour & CONTOUR_SRF) {
  1300.     for (i = 0; i < cntr->num_pts; i++) {
  1301.         map3d_xy(cntr->coords[i].x, cntr->coords[i].y, cntr->coords[i].z,
  1302.              &x, &y);
  1303.  
  1304.         if (i > 0) {
  1305.         clip_vector(x, y);
  1306.         if (i == 1)
  1307.             suppressMove = TRUE;
  1308.         } else {
  1309.         clip_move(x, y);
  1310.         }
  1311.     }
  1312.     }
  1313.     /* beginning a new contour level, so moveto() required */
  1314.     suppressMove = FALSE;
  1315.  
  1316.     if (draw_contour & CONTOUR_BASE) {
  1317.     for (i = 0; i < cntr->num_pts; i++) {
  1318.         map3d_xy(cntr->coords[i].x, cntr->coords[i].y, base_z,
  1319.              &x, &y);
  1320.  
  1321.         if (i > 0) {
  1322.         clip_vector(x, y);
  1323.         if (i == 1)
  1324.             suppressMove = TRUE;
  1325.         } else {
  1326.         clip_move(x, y);
  1327.         }
  1328.     }
  1329.     }
  1330.     /* beginning a new contour level, so moveto() required */
  1331.     suppressMove = FALSE;
  1332. }
  1333.  
  1334. /* cntr3d_points:
  1335.  * Plot a surface contour in POINTSTYLE style
  1336.  */
  1337. static void cntr3d_points(cntr, plot)
  1338. struct gnuplot_contours *cntr;
  1339. struct surface_points *plot;
  1340. {
  1341.     int i;
  1342.     unsigned int x, y;
  1343.     struct termentry *t = term;
  1344.  
  1345.     if (draw_contour & CONTOUR_SRF) {
  1346.     for (i = 0; i < cntr->num_pts; i++) {
  1347.         map3d_xy(cntr->coords[i].x, cntr->coords[i].y, cntr->coords[i].z, &x, &y);
  1348.  
  1349.         if (!clip_point(x, y))
  1350.         (*t->point) (x, y, plot->lp_properties.p_type);
  1351.     }
  1352.     }
  1353.     if (draw_contour & CONTOUR_BASE) {
  1354.     for (i = 0; i < cntr->num_pts; i++) {
  1355.         map3d_xy(cntr->coords[i].x, cntr->coords[i].y, base_z,
  1356.              &x, &y);
  1357.  
  1358.         if (!clip_point(x, y))
  1359.         (*t->point) (x, y, plot->lp_properties.p_type);
  1360.     }
  1361.     }
  1362. }
  1363.  
  1364. /* cntr3d_dots:
  1365.  * Plot a surface contour in DOTS style
  1366.  */
  1367. static void cntr3d_dots(cntr)
  1368. struct gnuplot_contours *cntr;
  1369. {
  1370.     int i;
  1371.     unsigned int x, y;
  1372.     struct termentry *t = term;
  1373.  
  1374.     if (draw_contour & CONTOUR_SRF) {
  1375.     for (i = 0; i < cntr->num_pts; i++) {
  1376.         map3d_xy(cntr->coords[i].x, cntr->coords[i].y, cntr->coords[i].z, &x, &y);
  1377.  
  1378.         if (!clip_point(x, y))
  1379.         (*t->point) (x, y, -1);
  1380.     }
  1381.     }
  1382.     if (draw_contour & CONTOUR_BASE) {
  1383.     for (i = 0; i < cntr->num_pts; i++) {
  1384.         map3d_xy(cntr->coords[i].x, cntr->coords[i].y, base_z,
  1385.              &x, &y);
  1386.  
  1387.         if (!clip_point(x, y))
  1388.         (*t->point) (x, y, -1);
  1389.     }
  1390.     }
  1391. }
  1392.  
  1393.  
  1394.  
  1395. /* map xmin | xmax to 0 | 1 and same for y
  1396.  * 0.1 avoids any rounding errors
  1397.  */
  1398. #define MAP_HEIGHT_X(x) ( (int) (((x)-x_min3d)/(x_max3d-x_min3d)+0.1) )
  1399. #define MAP_HEIGHT_Y(y) ( (int) (((y)-y_min3d)/(y_max3d-y_min3d)+0.1) )
  1400.  
  1401. /* if point is at corner, update height[][] and depth[][]
  1402.  * we are still assuming that extremes of surfaces are at corners,
  1403.  * but we are not assuming order of corners
  1404.  */
  1405. static void check_corner_height(p, height, depth)
  1406. struct coordinate GPHUGE *p;
  1407. double height[2][2];
  1408. double depth[2][2];
  1409. {
  1410.     if (p->type != INRANGE)
  1411.     return;
  1412.     if ((fabs(p->x - x_min3d) < zero || fabs(p->x - x_max3d) < zero) &&
  1413.     (fabs(p->y - y_min3d) < zero || fabs(p->y - y_max3d) < zero)) {
  1414.     unsigned int x = MAP_HEIGHT_X(p->x);
  1415.     unsigned int y = MAP_HEIGHT_Y(p->y);
  1416.     if (height[x][y] < p->z)
  1417.         height[x][y] = p->z;
  1418.     if (depth[x][y] > p->z)
  1419.         depth[x][y] = p->z;
  1420.     }
  1421. }
  1422.  
  1423.  
  1424. /* Draw the bottom grid that hold the tic marks for 3d surface. */
  1425. static void draw_bottom_grid(plot, plot_num)
  1426. struct surface_points *plot;
  1427. int plot_num;
  1428. {
  1429.     unsigned int x, y;        /* point in terminal coordinates */
  1430.     struct termentry *t = term;
  1431.     char ss[MAX_LINE_LEN+1];
  1432.  
  1433.     /* work out where the axes and tics are drawn */
  1434.  
  1435.     {
  1436.     int quadrant = surface_rot_z / 90;
  1437.     if ((quadrant + 1) & 2) {
  1438.         zaxis_x = x_max3d;
  1439.         xaxis_y = y_max3d;
  1440.     } else {
  1441.         zaxis_x = x_min3d;
  1442.         xaxis_y = y_min3d;
  1443.     }
  1444.  
  1445.     if (quadrant & 2) {
  1446.         zaxis_y = y_max3d;
  1447.         yaxis_x = x_min3d;
  1448.     } else {
  1449.         zaxis_y = y_min3d;
  1450.         yaxis_x = x_max3d;
  1451.     }
  1452.  
  1453.     if (surface_rot_x > 90) {
  1454.         /* labels on the back axes */
  1455.         back_x = yaxis_x = x_min3d + x_max3d - yaxis_x;
  1456.         back_y = xaxis_y = y_min3d + y_max3d - xaxis_y;
  1457.     } else {
  1458.         back_x = x_min3d + x_max3d - yaxis_x;
  1459.         back_y = y_min3d + y_max3d - xaxis_y;
  1460.     }
  1461.     }
  1462.  
  1463.     if (draw_border) {
  1464.     unsigned int bl_x, bl_y;    /* bottom left */
  1465.     unsigned int bb_x, bb_y;    /* bottom back */
  1466.     unsigned int br_x, br_y;    /* bottom right */
  1467.     unsigned int bf_x, bf_y;    /* bottom front */
  1468.  
  1469. #ifndef LITE
  1470.     int save_update = hidden_no_update;
  1471.     hidden_no_update = TRUE;
  1472. #endif /* LITE */
  1473.  
  1474.     /* Here is the one and only call to this function. */
  1475.     setlinestyle(border_lp);
  1476.  
  1477.     map3d_xy(zaxis_x, zaxis_y, base_z, &bl_x, &bl_y);
  1478.     map3d_xy(back_x, back_y, base_z, &bb_x, &bb_y);
  1479.     map3d_xy(x_min3d + x_max3d - zaxis_x, y_min3d + y_max3d - zaxis_y, base_z, &br_x, &br_y);
  1480.     map3d_xy(x_min3d + x_max3d - back_x, y_min3d + y_max3d - back_y, base_z, &bf_x, &bf_y);
  1481.  
  1482.     /* border around base */
  1483.     {
  1484.         int save = hidden_active;
  1485.         hidden_active = FALSE;    /* this is in front */
  1486.         if (draw_border & 4)
  1487.         draw_clip_line(br_x, br_y, bf_x, bf_y);
  1488.         if (draw_border & 1)
  1489.         draw_clip_line(bl_x, bl_y, bf_x, bf_y);
  1490.         hidden_active = save;
  1491.     }
  1492.     if (draw_border & 2)
  1493.         draw_clip_line(bl_x, bl_y, bb_x, bb_y);
  1494.     if (draw_border & 8)
  1495.         draw_clip_line(br_x, br_y, bb_x, bb_y);
  1496.  
  1497.     if (draw_surface || (draw_contour & CONTOUR_SRF)) {
  1498.         int save = hidden_active;
  1499.         /* map the 8 corners to screen */
  1500.         unsigned int fl_x, fl_y;    /* floor left */
  1501.         unsigned int fb_x, fb_y;    /* floor back */
  1502.         unsigned int fr_x, fr_y;    /* floor right */
  1503.         unsigned int ff_x, ff_y;    /* floor front */
  1504.  
  1505.         unsigned int tl_x, tl_y;    /* top left */
  1506.         unsigned int tb_x, tb_y;    /* top back */
  1507.         unsigned int tr_x, tr_y;    /* top right */
  1508.         unsigned int tf_x, tf_y;    /* top front */
  1509.  
  1510.         map3d_xy(zaxis_x, zaxis_y, floor_z, &fl_x, &fl_y);
  1511.         map3d_xy(back_x, back_y, floor_z, &fb_x, &fb_y);
  1512.         map3d_xy(x_min3d + x_max3d - zaxis_x, y_min3d + y_max3d - zaxis_y, floor_z, &fr_x, &fr_y);
  1513.         map3d_xy(x_min3d + x_max3d - back_x, y_min3d + y_max3d - back_y, floor_z, &ff_x, &ff_y);
  1514.  
  1515.         map3d_xy(zaxis_x, zaxis_y, ceiling_z, &tl_x, &tl_y);
  1516.         map3d_xy(back_x, back_y, ceiling_z, &tb_x, &tb_y);
  1517.         map3d_xy(x_min3d + x_max3d - zaxis_x, y_min3d + y_max3d - zaxis_y, ceiling_z, &tr_x, &tr_y);
  1518.         map3d_xy(x_min3d + x_max3d - back_x, y_min3d + y_max3d - back_y, ceiling_z, &tf_x, &tf_y);
  1519.  
  1520.         /* vertical lines, to surface or to very top */
  1521.         if ((draw_border & 0xf0) == 0xf0) {
  1522.         /* all four verticals drawn - save some time */
  1523.         draw_clip_line(fl_x, fl_y, tl_x, tl_y);
  1524.         draw_clip_line(fb_x, fb_y, tb_x, tb_y);
  1525.         draw_clip_line(fr_x, fr_y, tr_x, tr_y);
  1526.         hidden_active = FALSE;    /* this is in front */
  1527.         draw_clip_line(ff_x, ff_y, tf_x, tf_y);
  1528.         hidden_active = save;
  1529.         } else {
  1530.         /* search surfaces for heights at corners */
  1531.         double height[2][2];
  1532.         double depth[2][2];
  1533.         unsigned int zaxis_i = MAP_HEIGHT_X(zaxis_x);
  1534.         unsigned int zaxis_j = MAP_HEIGHT_Y(zaxis_y);
  1535.         unsigned int back_i = MAP_HEIGHT_X(back_x);
  1536.     /* HBB: why isn't back_j unsigned ??? */
  1537.         int back_j = MAP_HEIGHT_Y(back_y);
  1538.  
  1539.         height[0][0] = height[0][1] = height[1][0] = height[1][1] = base_z;
  1540.         depth[0][0] = depth[0][1] = depth[1][0] = depth[1][1] = base_z;
  1541.  
  1542.         for (; --plot_num >= 0; plot = plot->next_sp) {
  1543.             struct iso_curve *curve = plot->iso_crvs;
  1544.             int count = curve->p_count;
  1545.             int iso;
  1546.             if (plot->plot_type == DATA3D) {
  1547.             if (!plot->has_grid_topology)
  1548.                 continue;
  1549.             iso = plot->num_iso_read;
  1550.             } else
  1551.             iso = iso_samples_2;
  1552.  
  1553.             check_corner_height(curve->points, height, depth);
  1554.             check_corner_height(curve->points + count - 1, height, depth);
  1555.             while (--iso)
  1556.             curve = curve->next;
  1557.             check_corner_height(curve->points, height, depth);
  1558.             check_corner_height(curve->points + count - 1, height, depth);
  1559.         }
  1560.  
  1561. #define VERTICAL(mask,x,y,i,j,bx,by,tx,ty) \
  1562.  if (draw_border&mask) \
  1563.   draw_clip_line(bx,by,tx,ty);\
  1564. else if (height[i][j] != depth[i][j]) \
  1565. { unsigned int a0,b0, a1, b1; \
  1566.   map3d_xy(x,y,depth[i][j],&a0,&b0); \
  1567.   map3d_xy(x,y,height[i][j],&a1,&b1); \
  1568.   draw_clip_line(a0,b0,a1,b1); \
  1569. }
  1570.  
  1571.         VERTICAL(16,zaxis_x,zaxis_y,zaxis_i,zaxis_j,fl_x,fl_y,tl_x,tl_y);
  1572.         VERTICAL(32,back_x,back_y,back_i,back_j,fb_x,fb_y,tb_x,tb_y);
  1573.         VERTICAL(64,x_min3d+x_max3d-zaxis_x,y_min3d+y_max3d-zaxis_y,1-zaxis_i,1-zaxis_j,fr_x,fr_y,tr_x,tr_y);
  1574.         hidden_active = FALSE;
  1575.         VERTICAL(128,x_min3d+x_max3d-back_x,y_min3d+y_max3d-back_y,1-back_i,1-back_j,ff_x,ff_y,tf_x,tf_y);
  1576.             hidden_active = save;
  1577.         }
  1578.  
  1579.         /* now border lines on top */
  1580.         if (draw_border & 256)
  1581.         draw_clip_line(tl_x, tl_y, tb_x, tb_y);
  1582.         if (draw_border & 512)
  1583.         draw_clip_line(tr_x, tr_y, tb_x, tb_y);
  1584.         /* these lines are in front of surface (?) */
  1585.         hidden_active = FALSE;
  1586.         if (draw_border & 1024)
  1587.         draw_clip_line(tl_x, tl_y, tf_x, tf_y);
  1588.         if (draw_border & 2048)
  1589.         draw_clip_line(tr_x, tr_y, tf_x, tf_y);
  1590.         hidden_active = save;
  1591.     }
  1592.  
  1593. #ifndef LITE
  1594.     hidden_no_update = save_update;
  1595. #endif /* LITE */
  1596.  
  1597.     }
  1598.     if (xtics || *xlabel.text) {
  1599.     unsigned int x0, y0, x1, y1;
  1600.     double mid_x = (x_max3d + x_min3d) / 2;
  1601.     double len;
  1602.     map3d_xy(mid_x, xaxis_y, base_z, &x0, &y0);
  1603.     map3d_xy(mid_x, y_min3d + y_max3d - xaxis_y, base_z, &x1, &y1);
  1604.     {            /* take care over unsigned quantities */
  1605.         int dx = x1 - x0;
  1606.         int dy = y1 - y0;
  1607.         /* HBB 980309: 16bit strikes back: */
  1608.         len = sqrt(((double) dx) * dx + ((double) dy) * dy);
  1609.         if (len != 0) {
  1610.         tic_unitx = dx / len;
  1611.         tic_unity = dy / len;
  1612.         } else {
  1613.         tic_unitx = tic_unity = 0;
  1614.         }
  1615.     }
  1616.  
  1617.     if (xtics) {
  1618.         gen_tics(FIRST_X_AXIS, &xticdef,
  1619.              work_grid.l_type & (GRID_X | GRID_MX),
  1620.              mxtics, mxtfreq, xtick_callback);
  1621.     }
  1622.     if (*xlabel.text) {
  1623.         /* label at xaxis_y + 1/4 of (xaxis_y-other_y) */
  1624.         double step = (2 * xaxis_y - y_max3d - y_min3d) / 4;
  1625.         map3d_xy(mid_x, xaxis_y + step, base_z, &x1, &y1);
  1626.         x1 += xlabel.xoffset * t->h_char;
  1627.         y1 += xlabel.yoffset * t->v_char;
  1628.         if (!tic_in) {
  1629.         x1 -= tic_unitx * ticscale * (t->h_tic);
  1630.         y1 -= tic_unity * ticscale * (t->v_tic);
  1631.         }
  1632.         /* write_multiline mods it */
  1633.         write_multiline(x1, y1, xlabel.text, CENTRE, JUST_TOP, 0, xlabel.font);
  1634.     }
  1635.     }
  1636.     if (ytics || *ylabel.text) {
  1637.     unsigned int x0, y0, x1, y1;
  1638.     double mid_y = (y_max3d + y_min3d) / 2;
  1639.     double len;
  1640.     map3d_xy(yaxis_x, mid_y, base_z, &x0, &y0);
  1641.     map3d_xy(x_min3d + x_max3d - yaxis_x, mid_y, base_z, &x1, &y1);
  1642.     {            /* take care over unsigned quantities */
  1643.         int dx = x1 - x0;
  1644.         int dy = y1 - y0;
  1645.         /* HBB 980309: 16 Bits strike again: */
  1646.         len = sqrt(((double) dx) * dx + ((double) dy) * dy);
  1647.         if (len != 0) {
  1648.         tic_unitx = dx / len;
  1649.         tic_unity = dy / len;
  1650.         } else {
  1651.         tic_unitx = tic_unity = 0;
  1652.         }
  1653.     }
  1654.     if (ytics) {
  1655.         gen_tics(FIRST_Y_AXIS, &yticdef,
  1656.              work_grid.l_type & (GRID_Y | GRID_MY),
  1657.              mytics, mytfreq, ytick_callback);
  1658.     }
  1659.     if (*ylabel.text) {
  1660.         double step = (x_max3d + x_min3d - 2 * yaxis_x) / 4;
  1661.         map3d_xy(yaxis_x - step, mid_y, base_z, &x1, &y1);
  1662.         x1 += ylabel.xoffset * t->h_char;
  1663.         y1 += ylabel.yoffset * t->v_char;
  1664.         if (!tic_in) {
  1665.         x1 -= tic_unitx * ticscale * (t->h_tic);
  1666.         y1 -= tic_unity * ticscale * (t->v_tic);
  1667.         }
  1668.         /* write_multiline mods it */
  1669.         safe_strncpy(ss, ylabel.text, sizeof(ss));
  1670.         write_multiline(x1, y1, ss, CENTRE, JUST_TOP, 0, ylabel.font);
  1671.     }
  1672.     }
  1673.     /* do z tics */
  1674.  
  1675.     if (ztics && (draw_surface || (draw_contour & CONTOUR_SRF))) {
  1676.     gen_tics(FIRST_Z_AXIS, &zticdef, work_grid.l_type & (GRID_Z | GRID_MZ),
  1677.          mztics, mztfreq, ztick_callback);
  1678.     }
  1679.     if ((yzeroaxis.l_type >= -2) && !is_log_x && inrange(0, x_min3d, x_max3d)) {
  1680.     unsigned int x, y, x1, y1;
  1681.     term_apply_lp_properties(&yzeroaxis);
  1682.     map3d_xy(0.0, y_min3d, base_z, &x, &y);        /* line through x=0 */
  1683.     map3d_xy(0.0, y_max3d, base_z, &x1, &y1);
  1684.     draw_clip_line(x, y, x1, y1);
  1685.     }
  1686.     if ((xzeroaxis.l_type >= -2) && !is_log_y && inrange(0, y_min3d, y_max3d)) {
  1687.     unsigned int x, y, x1, y1;
  1688.     term_apply_lp_properties(&xzeroaxis);
  1689.     map3d_xy(x_min3d, 0.0, base_z, &x, &y);        /* line through y=0 */
  1690.     map3d_xy(x_max3d, 0.0, base_z, &x1, &y1);
  1691.     draw_clip_line(x, y, x1, y1);
  1692.     }
  1693.     /* PLACE ZLABEL - along the middle grid Z axis - eh ? */
  1694.     if (*zlabel.text && (draw_surface || (draw_contour & CONTOUR_SRF))) {
  1695.     map3d_xy(zaxis_x, zaxis_y, z_max3d + (z_max3d - base_z) / 4, &x, &y);
  1696.  
  1697.     x += zlabel.xoffset * t->h_char;
  1698.     y += zlabel.yoffset * t->v_char;
  1699.  
  1700.     write_multiline(x, y, zlabel.text, CENTRE, CENTRE, 0, zlabel.font);
  1701.  
  1702.     }
  1703. }
  1704.  
  1705.  
  1706. static void xtick_callback(axis, place, text, grid)
  1707. int axis;
  1708. double place;
  1709. char *text;
  1710. struct lp_style_type grid;    /* linetype or -2 for none */
  1711. {
  1712.     unsigned int x, y, x1, y1;
  1713.     double scale = (text ? ticscale : miniticscale);
  1714.     int dirn = tic_in ? 1 : -1;
  1715.     register struct termentry *t = term;
  1716.  
  1717.     map3d_xy(place, xaxis_y, base_z, &x, &y);
  1718.     if (grid.l_type > -2) {
  1719.     term_apply_lp_properties(&grid);
  1720.     /* to save mapping twice, map non-axis y */
  1721.     map3d_xy(place, y_min3d + y_max3d - xaxis_y, base_z, &x1, &y1);
  1722.     draw_clip_line(x, y, x1, y1);
  1723.     term_apply_lp_properties(&border_lp);
  1724.     }
  1725.     if (xtics & TICS_ON_AXIS) {
  1726.     map3d_xy(place, (y_min3d + y_max3d) / 2, base_z, &x, &y);
  1727.     }
  1728.     x1 = x + tic_unitx * scale * (t->h_tic) * dirn;
  1729.     y1 = y + tic_unity * scale * (t->v_tic) * dirn;
  1730.     draw_clip_line(x, y, x1, y1);
  1731.     if (text) {
  1732.     int just;
  1733.     if (tic_unitx < -0.9)
  1734.         just = LEFT;
  1735.     else if (tic_unitx < 0.9)
  1736.         just = CENTRE;
  1737.     else
  1738.         just = RIGHT;
  1739. #if 1
  1740. /* HBB 970729: let's see if the 'tic labels collide with axes' problem
  1741.  * may be fixed this way: */
  1742.     x1 = x - tic_unitx * (t->h_char) * 1;
  1743.     y1 = y - tic_unity * (t->v_char) * 1;
  1744. #else
  1745.     x1 = x - tic_unitx * (t->h_tic) * 2;
  1746.     y1 = y - tic_unity * (t->v_tic) * 2;
  1747. #endif
  1748.     if (!tic_in) {
  1749.         x1 -= tic_unitx * (t->h_tic) * ticscale;
  1750.         y1 -= tic_unity * (t->v_tic) * ticscale;
  1751.     }
  1752.     clip_put_text_just(x1, y1, text, just);
  1753.     }
  1754.     if (xtics & TICS_MIRROR) {
  1755.     map3d_xy(place, y_min3d + y_max3d - xaxis_y, base_z, &x, &y);
  1756.     x1 = x - tic_unitx * scale * (t->h_tic) * dirn;
  1757.     y1 = y - tic_unity * scale * (t->v_tic) * dirn;
  1758.     draw_clip_line(x, y, x1, y1);
  1759.     }
  1760. }
  1761.  
  1762. static void ytick_callback(axis, place, text, grid)
  1763. int axis;
  1764. double place;
  1765. char *text;
  1766. struct lp_style_type grid;
  1767. {
  1768.     unsigned int x, y, x1, y1;
  1769.     double scale = (text ? ticscale : miniticscale);
  1770.     int dirn = tic_in ? 1 : -1;
  1771.     register struct termentry *t = term;
  1772.  
  1773.     map3d_xy(yaxis_x, place, base_z, &x, &y);
  1774.     if (grid.l_type > -2) {
  1775.     term_apply_lp_properties(&grid);
  1776.     map3d_xy(x_min3d + x_max3d - yaxis_x, place, base_z, &x1, &y1);
  1777.     draw_clip_line(x, y, x1, y1);
  1778.     term_apply_lp_properties(&border_lp);
  1779.     }
  1780.     if (ytics & TICS_ON_AXIS) {
  1781.     map3d_xy((x_min3d + x_max3d) / 2, place, base_z, &x, &y);
  1782.     }
  1783.     x1 = x + tic_unitx * scale * dirn * (t->h_tic);
  1784.     y1 = y + tic_unity * scale * dirn * (t->v_tic);
  1785.     draw_clip_line(x, y, x1, y1);
  1786.     if (text) {
  1787.     int just;
  1788.     if (tic_unitx < -0.9)
  1789.         just = LEFT;
  1790.     else if (tic_unitx < 0.9)
  1791.         just = CENTRE;
  1792.     else
  1793.         just = RIGHT;
  1794. #if 1
  1795.     /* HBB 970729: same as above in xtics_callback */
  1796.     x1 = x - tic_unitx * (t->h_char) * 1;
  1797.     y1 = y - tic_unity * (t->v_char) * 1;
  1798. #else
  1799.     x1 = x - tic_unitx * (t->h_tic) * 2;
  1800.     y1 = y - tic_unity * (t->v_tic) * 2;
  1801. #endif
  1802.     if (!tic_in) {
  1803.         x1 -= tic_unitx * (t->h_tic) * ticscale;
  1804.         y1 -= tic_unity * (t->v_tic) * ticscale;
  1805.     }
  1806.     clip_put_text_just(x1, y1, text, just);
  1807.     }
  1808.     if (ytics & TICS_MIRROR) {
  1809.     map3d_xy(x_min3d + x_max3d - yaxis_x, place, base_z, &x, &y);
  1810.     x1 = x - tic_unitx * scale * (t->h_tic) * dirn;
  1811.     y1 = y - tic_unity * scale * (t->v_tic) * dirn;
  1812.     draw_clip_line(x, y, x1, y1);
  1813.     }
  1814. }
  1815.  
  1816. static void ztick_callback(axis, place, text, grid)
  1817. int axis;
  1818. double place;
  1819. char *text;
  1820. struct lp_style_type grid;
  1821. {
  1822. /* HBB: inserted some ()'s to shut up gcc -Wall, here and below */
  1823.     int len = (text ? ticscale : miniticscale) * (tic_in ? 1 : -1) * (term->h_tic);
  1824.     unsigned int x, y;
  1825.  
  1826.     if (grid.l_type > -2) {
  1827.     unsigned int x1, y1, x2, y2, x3, y3;
  1828.     double other_x = x_min3d + x_max3d - zaxis_x;
  1829.     double other_y = y_min3d + y_max3d - zaxis_y;
  1830.     term_apply_lp_properties(&grid);
  1831.     map3d_xy(zaxis_x, zaxis_y, place, &x1, &y1);
  1832.     map3d_xy(back_x, back_y, place, &x2, &y2);
  1833.     map3d_xy(other_x, other_y, place, &x3, &y3);
  1834.     draw_clip_line(x1, y1, x2, y2);
  1835.     draw_clip_line(x2, y2, x3, y3);
  1836.     term_apply_lp_properties(&border_lp);
  1837.     }
  1838.     map3d_xy(zaxis_x, zaxis_y, place, &x, &y);
  1839.     draw_clip_line(x, y, x + len, y);
  1840.     if (text) {
  1841.     int x1 = x - (term->h_tic) * 2;
  1842.     if (!tic_in)
  1843.         x1 -= (term->h_tic) * ticscale;
  1844.     clip_put_text_just(x1, y, text, RIGHT);
  1845.     }
  1846.     if (ztics & TICS_MIRROR) {
  1847.     double other_x = x_min3d + x_max3d - zaxis_x;
  1848.     double other_y = y_min3d + y_max3d - zaxis_y;
  1849.     map3d_xy(other_x, other_y, place, &x, &y);
  1850.     draw_clip_line(x, y, x - len, y);
  1851.     }
  1852. }
  1853.  
  1854.  
  1855. static void map_position(pos, x, y, what)
  1856. struct position *pos;
  1857. unsigned int *x, *y;
  1858. char *what;
  1859. {
  1860.     double xpos = pos->x;
  1861.     double ypos = pos->y;
  1862.     double zpos = pos->z;
  1863.     int screens = 0;        /* need either 0 or 3 screen co-ordinates */
  1864.  
  1865.     switch (pos->scalex) {
  1866.     case first_axes:
  1867.     case second_axes:
  1868.     xpos = LogScale(xpos, is_log_x, log_base_log_x, what, "x");
  1869.     break;
  1870.     case graph:
  1871.     xpos = min_array[FIRST_X_AXIS] +
  1872.         xpos * (max_array[FIRST_X_AXIS] - min_array[FIRST_X_AXIS]);
  1873.     break;
  1874.     case screen:
  1875.     ++screens;
  1876.     }
  1877.  
  1878.     switch (pos->scaley) {
  1879.     case first_axes:
  1880.     case second_axes:
  1881.     ypos = LogScale(ypos, is_log_y, log_base_log_y, what, "y");
  1882.     break;
  1883.     case graph:
  1884.     ypos = min_array[FIRST_Y_AXIS] +
  1885.         ypos * (max_array[FIRST_Y_AXIS] - min_array[FIRST_Y_AXIS]);
  1886.     break;
  1887.     case screen:
  1888.     ++screens;
  1889.     }
  1890.  
  1891.     switch (pos->scalez) {
  1892.     case first_axes:
  1893.     case second_axes:
  1894.     zpos = LogScale(zpos, is_log_z, log_base_log_z, what, "z");
  1895.     break;
  1896.     case graph:
  1897.     zpos = min_array[FIRST_Z_AXIS] +
  1898.         zpos * (max_array[FIRST_Z_AXIS] - min_array[FIRST_Z_AXIS]);
  1899.     break;
  1900.     case screen:
  1901.     ++screens;
  1902.     }
  1903.  
  1904.     if (screens == 0) {
  1905.     map3d_xy(xpos, ypos, zpos, x, y);
  1906.     return;
  1907.     }
  1908.     if (screens != 3) {
  1909.     graph_error("Cannot mix screen co-ordinates with other types");
  1910.     } {
  1911.     register struct termentry *t = term;
  1912.     *x = pos->x * (t->xmax) + 0.5;
  1913.     *y = pos->y * (t->ymax) + 0.5;
  1914.     }
  1915.  
  1916.     return;
  1917. }
  1918.  
  1919.  
  1920. /*
  1921.  * these code blocks were moved to functions, to make the code simpler
  1922.  */
  1923.  
  1924. static void key_text(xl, yl, text)
  1925. int xl, yl;
  1926. char *text;
  1927. {
  1928.     if (key_just == JLEFT && key == -1) {
  1929.     (*term->justify_text) (LEFT);
  1930.     (*term->put_text) (xl + key_text_left, yl, text);
  1931.     } else {
  1932.     if ((*term->justify_text) (RIGHT)) {
  1933.         if (key == 1)
  1934.         clip_put_text(xl + key_text_right, yl, text);
  1935.         else
  1936.         (*term->put_text) (xl + key_text_right, yl, text);
  1937.     } else {
  1938.         int x = xl + key_text_right - (term->h_char) * strlen(text);
  1939.         if (key == 1) {
  1940.         if (i_inrange(x, xleft, xright))
  1941.             clip_put_text(x, yl, text);
  1942.         } else {
  1943.         (*term->put_text) (x, yl, text);
  1944.         }
  1945.     }
  1946.     }
  1947. }
  1948.  
  1949. static void key_sample_line(xl, yl)
  1950. int xl, yl;
  1951. {
  1952.     if (key == -1) {
  1953.     (*term->move) (xl + key_sample_left, yl);
  1954.     (*term->vector) (xl + key_sample_right, yl);
  1955.     } else {
  1956.     /* HBB 981118: avoid crash if hidden3d sees a manually placed key:
  1957.      * simply turn off hidden-lining while we're drawing the key line: */
  1958.     int save_hidden_active = hidden_active;
  1959.     hidden_active = FALSE;
  1960.  
  1961.     clip_move(xl + key_sample_left, yl);
  1962.     clip_vector(xl + key_sample_right, yl);
  1963.     hidden_active = save_hidden_active;
  1964.     }
  1965. }
  1966.  
  1967. static void key_sample_point(xl, yl, pointtype)
  1968. int xl, yl;
  1969. int pointtype;
  1970. {
  1971.     if (!clip_point(xl + key_point_offset, yl)) {
  1972.     (*term->point) (xl + key_point_offset, yl, pointtype);
  1973.     } else {
  1974.     (*term->point) (xl + key_point_offset, yl, pointtype);
  1975.     }
  1976. }
  1977.